﻿namespace Microsoft.SharePoint.Client
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Xml;

    public static class DataConvert
    {
        private static Type s_ilistType = typeof(IList<object>).GetGenericTypeDefinition();
        private static Type s_listType = typeof(List<object>).GetGenericTypeDefinition();
        private static Dictionary<string, Type> s_strongTypedArrayElementTypeNames;
        private static WriteValueHandler s_writeValueEnum;
        private static Dictionary<Type, WriteValueHandler> s_writeValueHandlers = new Dictionary<Type, WriteValueHandler>();
        private static Dictionary<Type, string> s_writeValueTypeNames = new Dictionary<Type, string>();

        static DataConvert()
        {
            s_writeValueHandlers[typeof(bool)] = new WriteValueHandler(DataConvert.WriteValue_Boolean);
            s_writeValueTypeNames[typeof(bool)] = "Boolean";
            s_writeValueHandlers[typeof(char)] = new WriteValueHandler(DataConvert.WriteValue_Char);
            s_writeValueTypeNames[typeof(char)] = "Char";
            s_writeValueHandlers[typeof(byte)] = new WriteValueHandler(DataConvert.WriteValue_Byte);
            s_writeValueTypeNames[typeof(byte)] = "Byte";
            s_writeValueHandlers[typeof(sbyte)] = new WriteValueHandler(DataConvert.WriteValue_SByte);
            s_writeValueTypeNames[typeof(sbyte)] = "SByte";
            s_writeValueHandlers[typeof(short)] = new WriteValueHandler(DataConvert.WriteValue_Int16);
            s_writeValueTypeNames[typeof(short)] = "Int16";
            s_writeValueHandlers[typeof(ushort)] = new WriteValueHandler(DataConvert.WriteValue_UInt16);
            s_writeValueTypeNames[typeof(ushort)] = "UInt16";
            s_writeValueHandlers[typeof(int)] = new WriteValueHandler(DataConvert.WriteValue_Int32);
            s_writeValueTypeNames[typeof(int)] = "Int32";
            s_writeValueHandlers[typeof(uint)] = new WriteValueHandler(DataConvert.WriteValue_UInt32);
            s_writeValueTypeNames[typeof(uint)] = "UInt32";
            s_writeValueHandlers[typeof(long)] = new WriteValueHandler(DataConvert.WriteValue_Int64);
            s_writeValueTypeNames[typeof(long)] = "Int64";
            s_writeValueHandlers[typeof(ulong)] = new WriteValueHandler(DataConvert.WriteValue_UInt64);
            s_writeValueTypeNames[typeof(ulong)] = "UInt64";
            s_writeValueHandlers[typeof(float)] = new WriteValueHandler(DataConvert.WriteValue_Single);
            s_writeValueTypeNames[typeof(float)] = "Single";
            s_writeValueHandlers[typeof(double)] = new WriteValueHandler(DataConvert.WriteValue_Double);
            s_writeValueTypeNames[typeof(double)] = "Double";
            s_writeValueHandlers[typeof(DateTime)] = new WriteValueHandler(DataConvert.WriteValue_DateTime);
            s_writeValueTypeNames[typeof(DateTime)] = "DateTime";
            s_writeValueHandlers[typeof(Guid)] = new WriteValueHandler(DataConvert.WriteValue_Guid);
            s_writeValueTypeNames[typeof(Guid)] = "Guid";
            s_writeValueHandlers[typeof(string)] = new WriteValueHandler(DataConvert.WriteValue_String);
            s_writeValueTypeNames[typeof(string)] = "String";
            s_writeValueHandlers[typeof(byte[])] = new WriteValueHandler(DataConvert.WriteValue_ByteArray);
            s_writeValueTypeNames[typeof(byte[])] = "Base64Binary";
            s_writeValueEnum = new WriteValueHandler(DataConvert.WriteValue_Enum);
            s_strongTypedArrayElementTypeNames = new Dictionary<string, Type>();
            s_strongTypedArrayElementTypeNames["Boolean"] = typeof(bool);
            s_strongTypedArrayElementTypeNames["Char"] = typeof(char);
            s_strongTypedArrayElementTypeNames["Byte"] = typeof(byte);
            s_strongTypedArrayElementTypeNames["SByte"] = typeof(sbyte);
            s_strongTypedArrayElementTypeNames["Int16"] = typeof(short);
            s_strongTypedArrayElementTypeNames["UInt16"] = typeof(ushort);
            s_strongTypedArrayElementTypeNames["Int32"] = typeof(int);
            s_strongTypedArrayElementTypeNames["UInt32"] = typeof(uint);
            s_strongTypedArrayElementTypeNames["Int64"] = typeof(long);
            s_strongTypedArrayElementTypeNames["UInt64"] = typeof(ulong);
            s_strongTypedArrayElementTypeNames["DateTime"] = typeof(DateTime);
            s_strongTypedArrayElementTypeNames["Single"] = typeof(float);
            s_strongTypedArrayElementTypeNames["Double"] = typeof(double);
            s_strongTypedArrayElementTypeNames["Guid"] = typeof(Guid);
            s_strongTypedArrayElementTypeNames["String"] = typeof(string);
        }

        private static bool CouldSerializeDictionaryEntry(object objValue)
        {
            if (objValue == null)
            {
                return true;
            }
            if ((objValue is ClientObject) || (objValue is ClientValueObject))
            {
                return true;
            }
            Type type = objValue.GetType();
            if ((type.IsPrimitive || type.IsEnum) || ((type == typeof(Guid)) || (type == typeof(string))))
            {
                return true;
            }
            if (type.IsArray)
            {
                Type elementType = type.GetElementType();
                if ((elementType.IsPrimitive || elementType.IsEnum) || ((elementType == typeof(Guid)) || (elementType == typeof(string))))
                {
                    return true;
                }
            }
            return false;
        }

        internal static string GetTypeName(Type type)
        {
            return s_writeValueTypeNames[type];
        }

        public static void WriteDictionaryToXml(XmlWriter writer, Dictionary<string, object> dict, string topLevelElementTagName, string[] keys, SerializationContext serializationContext)
        {
            if (!string.IsNullOrEmpty(topLevelElementTagName))
            {
                writer.WriteStartElement(topLevelElementTagName);
            }
            foreach (KeyValuePair<string, object> pair in dict)
            {
                if ((keys == null) || (Array.IndexOf<string>(keys, pair.Key) >= 0))
                {
                    writer.WriteStartElement("Property");
                    writer.WriteAttributeString("Name", pair.Key.ToString());
                    object objValue = pair.Value;
                    WriteValueToXmlElement(writer, objValue, serializationContext);
                    writer.WriteEndElement();
                }
            }
            if (!string.IsNullOrEmpty(topLevelElementTagName))
            {
                writer.WriteEndElement();
            }
        }

        private static void WriteValue_Boolean(XmlWriter writer, object objValue)
        {
            writer.WriteValue((bool) objValue);
        }

        private static void WriteValue_Byte(XmlWriter writer, object objValue)
        {
            byte num = (byte) objValue;
            writer.WriteValue((int) num);
        }

        private static void WriteValue_ByteArray(XmlWriter writer, object objValue)
        {
            byte[] buffer = (byte[]) objValue;
            writer.WriteValue(buffer);
        }

        private static void WriteValue_Char(XmlWriter writer, object objValue)
        {
            writer.WriteValue(((char) objValue).ToString());
        }

        private static void WriteValue_DateTime(XmlWriter writer, object objValue)
        {
            string text = ((DateTime) objValue).ToString("o", CultureInfo.InvariantCulture);
            writer.WriteString(text);
        }

        private static void WriteValue_Double(XmlWriter writer, object objValue)
        {
            double num = (double) objValue;
            writer.WriteValue(num);
        }

        private static void WriteValue_Enum(XmlWriter writer, object objValue)
        {
            Type underlyingType = Enum.GetUnderlyingType(objValue.GetType());
            object obj2 = Convert.ChangeType(objValue, underlyingType, CultureInfo.InvariantCulture);
            writer.WriteValue(obj2);
        }

        private static void WriteValue_Guid(XmlWriter writer, object objValue)
        {
            writer.WriteString(((Guid) objValue).ToString("B"));
        }

        private static void WriteValue_Int16(XmlWriter writer, object objValue)
        {
            short num = (short) objValue;
            writer.WriteValue((int) num);
        }

        private static void WriteValue_Int32(XmlWriter writer, object objValue)
        {
            writer.WriteValue((int) objValue);
        }

        private static void WriteValue_Int64(XmlWriter writer, object objValue)
        {
            long num = (long) objValue;
            writer.WriteValue(num);
        }

        private static void WriteValue_SByte(XmlWriter writer, object objValue)
        {
            sbyte num = (sbyte) objValue;
            writer.WriteValue((int) num);
        }

        private static void WriteValue_Single(XmlWriter writer, object objValue)
        {
            float num = (float) objValue;
            writer.WriteValue(num);
        }

        private static void WriteValue_String(XmlWriter writer, object objValue)
        {
            string text = (string) objValue;
            writer.WriteString(text);
        }

        private static void WriteValue_UInt16(XmlWriter writer, object objValue)
        {
            ushort num = (ushort) objValue;
            writer.WriteValue((int) num);
        }

        private static void WriteValue_UInt32(XmlWriter writer, object objValue)
        {
            uint num = (uint) objValue;
            writer.WriteValue((long) num);
        }

        private static void WriteValue_UInt64(XmlWriter writer, object objValue)
        {
            writer.WriteString(((ulong) objValue).ToString(CultureInfo.InvariantCulture));
        }

        public static void WriteValueToXmlElement(XmlWriter writer, object objValue, SerializationContext serializationContext)
        {
            if (objValue == null)
            {
                writer.WriteAttributeString("Type", "Null");
            }
            else if (objValue is ClientObject)
            {
                ClientObject obj2 = (ClientObject) objValue;
                if (obj2.Path == null)
                {
                    throw new ClientRequestException(Resources.GetString("NoObjectPathAssociatedWithObject"));
                }
                writer.WriteAttributeString("ObjectPathId", obj2.Path.Id.ToString());
                serializationContext.AddClientObject(obj2);
            }
            else if (objValue is ClientValueObject)
            {
                ClientValueObject obj3 = (ClientValueObject) objValue;
                writer.WriteAttributeString("TypeId", obj3.TypeId);
                if (!obj3.CustomWriteToXml(writer, serializationContext))
                {
                    obj3.WriteToXml(writer, serializationContext);
                }
            }
            else
            {
                WriteValueHandler handler = null;
                if (s_writeValueHandlers.TryGetValue(objValue.GetType(), out handler))
                {
                    writer.WriteAttributeString("Type", s_writeValueTypeNames[objValue.GetType()]);
                    handler(writer, objValue);
                }
                else if (objValue.GetType().IsArray)
                {
                    writer.WriteAttributeString("Type", "Array");
                    foreach (object obj4 in (Array) objValue)
                    {
                        if (obj4 != null)
                        {
                            writer.WriteStartElement("Object");
                            WriteValueToXmlElement(writer, obj4, serializationContext);
                            writer.WriteEndElement();
                        }
                    }
                }
                else if (objValue.GetType().IsGenericType && ((objValue.GetType().GetGenericTypeDefinition() == s_ilistType) || (objValue.GetType().GetGenericTypeDefinition() == s_listType)))
                {
                    writer.WriteAttributeString("Type", "Array");
                    foreach (object obj5 in (IEnumerable) objValue)
                    {
                        writer.WriteStartElement("Object");
                        WriteValueToXmlElement(writer, obj5, serializationContext);
                        writer.WriteEndElement();
                    }
                }
                else if (objValue is IDictionary)
                {
                    writer.WriteAttributeString("Type", "Dictionary");
                    IDictionaryEnumerator enumerator = (objValue as IDictionary).GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        if (CouldSerializeDictionaryEntry(enumerator.Value) && (enumerator.Key is string))
                        {
                            writer.WriteStartElement("Property");
                            writer.WriteAttributeString("Name", (string) enumerator.Key);
                            WriteValueToXmlElement(writer, enumerator.Value, serializationContext);
                            writer.WriteEndElement();
                        }
                    }
                }
                else if (objValue.GetType().IsEnum)
                {
                    writer.WriteAttributeString("Type", "Enum");
                    s_writeValueEnum(writer, objValue);
                }
                else
                {
                    writer.WriteAttributeString("Type", "Unspecified");
                    writer.WriteString(objValue.ToString());
                }
            }
        }

        internal static Dictionary<string, Type> StrongTypedArrayElementTypeNames
        {
            get
            {
                return s_strongTypedArrayElementTypeNames;
            }
        }

        private delegate void WriteValueHandler(XmlWriter writer, object objValue);
    }
}

